/*
 * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.love.cloud.admin.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.love.cloud.admin.api.constants.SelectTypeConstants;
import com.love.cloud.admin.api.dto.CustomGroupDto;
import com.love.cloud.admin.api.dto.DeptUsersDto;
import com.love.cloud.admin.api.dto.UserDTO;
import com.love.cloud.admin.api.dto.UserInfo;
import com.love.cloud.admin.api.entity.*;
import com.love.cloud.admin.api.vo.*;
import com.love.cloud.admin.config.properties.SosSecurityProperties;
import com.love.cloud.admin.mapper.SysDeptMapper;
import com.love.cloud.admin.mapper.SysOauthClientDetailsMapper;
import com.love.cloud.admin.mapper.SysUserMapper;
import com.love.cloud.admin.service.*;
import com.love.cloud.auth.api.SosAuthProvider;
import com.love.cloud.common.core.constant.CacheConstants;
import com.love.cloud.common.core.constant.CommonConstants;
import com.love.cloud.common.core.exception.BusinessException;
import com.love.cloud.common.core.util.HandlePasswordUtil;
import com.love.cloud.common.core.util.RedisUtils;
import com.love.cloud.common.security.service.SosUser;
import com.love.cloud.common.security.util.SecurityUtils;
import com.love.cloud.common.zzd.properties.DingTalkProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lengleng
 * @date 2019/2/1
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
	private static final String KEY_ALGORITHM = "AES";
	private static final String defaultPassword = "WD*vSeNs9uhBmGEF";
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();


	// 密匙
	private final String privateKey="MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==";
	// 公匙
	private final String publicKey="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==";

	@Resource
	private SosSecurityProperties sosSecurityProperties;
	@Resource
	private DingTalkProperties dingTalkProperties;
	@Resource
	private SysMenuService sysMenuService;
	@Resource
	private SysRoleService sysRoleService;
	@Resource
	private SysDeptService sysDeptService;
	@Resource
	private SysUserRoleService sysUserRoleService;
	@Resource
	private SysUserDeptService sysUserDeptService;
	@Resource
	private SysDeptMapper sysDeptMapper;
	@Resource
	private SysCustomGroupService sysCustomGroupService;
	@Resource
	private CacheManager cacheManager;
	@Resource
	private RedisUtils redisUtils;
	@Resource
	private SysOauthClientDetailsMapper sysOauthClientDetailsMapper;

	@DubboReference(version = "1.0.0", timeout = 30000)
	private SosAuthProvider sosAuthProvider;

	/**
	 * 保存用户信息
	 * @param userDto DTO 对象
	 * @return success/fail
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public SysUser saveUser(UserDTO userDto) {
		SysUser sysUser = this.getSaveUser(userDto);
		//判断手机号是否存在
		if(StringUtils.isNotEmpty(userDto.getMobile())){
			QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
			queryWrapper.lambda().eq(SysUser::getMobile,userDto.getMobile());
			if(count(queryWrapper)>0){
				new BusinessException("手机号码已被使用");
			}
		}
		//判断用户名是否存在
		QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
		queryWrapper.lambda().eq(SysUser::getUsername,sysUser.getUsername());
		int count = count(queryWrapper);
		if(count>0){
			sysUser.setUsername(sysUser.getUsername()+(count+1));
		}
		baseMapper.insert(sysUser);
		if(userDto.getRole()!=null&&userDto.getRole().size()>0){
			//保存角色信息
			List<SysUserRole> userRoleList = userDto.getRole().stream().map(roleId -> {
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(sysUser.getId());
				userRole.setRoleId(roleId);
				return userRole;
			}).collect(Collectors.toList());
			sysUserRoleService.saveBatch(userRoleList);
		}
		if(userDto.getDept()!=null&&userDto.getDept().size()>0){
			//保存部门信息
			List<SysUserDept> userDeptList = userDto.getDept().stream().map(deptId -> {
				SysUserDept userDept = new SysUserDept();
				userDept.setUserId(sysUser.getId());
				userDept.setDeptId(deptId);
				userDept.setSource(sysUser.getSource());
				return userDept;
			}).collect(Collectors.toList());
			sysUserDeptService.saveBatch(userDeptList);
		}
		//删除选人组件的数据
		this.clearSelectUserData();
		return sysUser;
	}

	@Override
	public SysUser getSaveUser(UserDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		if (StringUtils.isNotEmpty(sysUser.getPassword())) {
			//校验弱密码
			boolean weekPassword = HandlePasswordUtil.isWeekPassword(sysUser.getPassword());
			if(weekPassword){
				throw new BusinessException("当前密码是弱密码");
			}
			sysUser.setPassword(ENCODER.encode(sysUser.getPassword()));
		}else{
			sysUser.setPassword(ENCODER.encode(defaultPassword));
		}
		//如果没设置状态默认设置开启状态
		if(StringUtils.isEmpty(userDto.getStatus())){
			userDto.setStatus(CommonConstants.STATUS_NORMAL);
		}
		sysUser.setFirstSpell(PinyinUtil.getFirstLetter(sysUser.getName(),""));
		sysUser.setSpell(PinyinUtil.getPinyin(sysUser.getName(),""));
		return sysUser;
	}

	/**
	 * 通过查用户的全部信息
	 * @param sysUser 用户
	 * @return
	 */
	@Override
	public UserInfo getUserInfo(SysUser sysUser) {
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		// 设置角色列表 （ID）
		List<SysRole> sysRoleList = sysRoleService.findRolesByUserId(sysUser.getId());
		userInfo.setRoles(sysRoleList);

		// 设置权限列表（menu.permission）
		Set<String> permissions = new HashSet<>();
		sysRoleList.forEach(role -> {
			List<String> permissionList = sysMenuService.findMenuByRoleId(role.getRoleId()).stream()
					.filter(menuVo -> StrUtil.isNotEmpty(menuVo.getPermission())).map(SysMenu::getPermission)
					.collect(Collectors.toList());
			permissions.addAll(permissionList);
		});
		List<SysDept> sysDeptList = sysDeptMapper.listDeptByUserId(sysUser.getId());
		userInfo.setSysDeptList(sysDeptList);
		userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
		return userInfo;
	}

	/**
	 * 分页查询用户信息（含有角色信息）
	 * @param page 分页对象
	 * @param userDTO 参数列表
	 * @return
	 */
	@Override
	public IPage getUserWithRolePage(Page page, UserDTO userDTO) {
		//同时查询其余两个条件
		if(StringUtils.isNotEmpty(userDTO.getName())){
			userDTO.setFirstSpell(userDTO.getName().toLowerCase());
			userDTO.setSpell(userDTO.getName().toLowerCase());
		}
		return baseMapper.getUserVosPage(page, userDTO);
	}

	/**
	 * 通过ID查询用户信息
	 * @param id 用户ID
	 * @return 用户信息
	 */
	@Override
	public UserVO getUserVoById(Long id) {
		return baseMapper.getUserVoById(id);
	}

	/**
	 * 删除用户
	 * @param sysUser 用户
	 * @return Boolean
	 */
	@Override
	public Boolean removeUserById(SysUser sysUser) {
		sysUserRoleService.removeRoleByUserId(sysUser.getId());
		this.removeById(sysUser.getId());
		//清理缓存
		this.clearUserDetailCache(sysUser.getId());
		return Boolean.TRUE;
	}

	@Override
	public Boolean updateUserInfo(UserDTO userDto) {
		UserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());
		SysUser sysUser = new SysUser();
		//修改手机号
		sysUser.setMobile(userDto.getMobile());
		sysUser.setId(userVO.getId());
		//修改用户照片
		sysUser.setAvatar(userDto.getAvatar());
		boolean b = this.updateById(sysUser);
		this.clearUserDetailCache(userVO.getId());
		return b;
	}

	@Override
	public Boolean changePassword(UserDTO userDto) {
		//判断密码是否上传了
		if(StringUtils.isEmpty(userDto.getPassword())){
			throw new BusinessException("请传入旧密码");
		}
		if(StringUtils.isEmpty(userDto.getNewpassword1())){
			throw new BusinessException("请传入新密码");
		}
		if(userDto.getId()==null){
			throw new BusinessException("请传入用户id");
		}
		//获取到原来的用户信息
		SysUser sysUser = this.getById(userDto.getId());
		String newPassword="";
		String password="";
		//解密
		try {
			newPassword = decryptAES(userDto.getNewpassword1(), sosSecurityProperties.getEncodeKey());
			password = decryptAES(userDto.getPassword(), sosSecurityProperties.getEncodeKey());
		}catch (Exception e) {
			throw new BusinessException("密码解密失败");
		}
		//检验原密码
		if(!ENCODER.matches(password.trim(), sysUser.getPassword())){
			throw new BusinessException("原密码错误，修改失败");
		}
		//校验新密码强度
		//校验弱密码
		boolean weekPassword = HandlePasswordUtil.isWeekPassword(sysUser.getPassword());
		if(weekPassword){
			throw new BusinessException("新密码是弱密码");
		}
		//修改密码
		sysUser.setPassword(ENCODER.encode(newPassword.trim()));
		this.updateById(sysUser);
		//清理缓存
		this.clearUserDetailCache(sysUser);
		return true;
	}

	@Override
	public Boolean resetPassword(UserDTO userDto) {
		if(userDto.getId()==null){
			throw new BusinessException("请传入用户id");
		}
		//获取到原来的用户信息
		SysUser sysUser = this.getById(userDto.getId());
		//重置密码为初始密码
		String password=defaultPassword;
		if(StringUtils.isNotEmpty(dingTalkProperties.getPassword())){
			password=dingTalkProperties.getPassword();
		}
		sysUser.setPassword(ENCODER.encode(password));
		this.updateById(sysUser);
		//清理缓存
		this.clearUserDetailCache(sysUser);
		return true;
	}

	@Override
	public Object getForgetPasswordValidCode(ForgetPasswordVo forgetPasswordVo) {
		//校验手机号
		this.getUserByMobile(forgetPasswordVo.getMobile());
		//查看缓存中验证码是否还有效
		Object o = redisUtils.get("ForgetPasswordValidCode::" + forgetPasswordVo.getMobile());
		if(o!=null){
			// todo 目前没有短信机直接返回验证码，后续有短信机把返回值去掉
			return String.valueOf(o);
		}
		//获取到验证码
		String kaptcha = this.getKaptcha();
		//发送短信验证码 todo 根据你的短信机
		//保存到redis,时效1分钟
		redisUtils.set("ForgetPasswordValidCode::"+forgetPasswordVo.getMobile(),kaptcha,1*60);
		// todo 发送短信
		// todo 目前没有短信机直接返回验证码，后续有短信机把返回值去掉
		return kaptcha;
	}

	@Override
	public Object checkForgetPasswordValidCode(ForgetPasswordVo forgetPasswordVo) {
		Object o = redisUtils.get("ForgetPasswordValidCode::" + forgetPasswordVo.getMobile());
		if(o==null){
			throw new BusinessException("请输入正确的验证信息");
		}
		if(!forgetPasswordVo.getValidCode().equals(o.toString())){
			throw new BusinessException("验证码不正确");
		}
		//删除掉缓存中的验证码
		redisUtils.del("ForgetPasswordValidCode::" + forgetPasswordVo.getMobile());
		//获取到转化成功后的真实编码
		String checkSuccessCode = this.getKaptcha();
		//校验成功之后生成加密的编码
		// 公钥加密
		RSA rsa = new RSA(null, publicKey);
		String encryptedSuccessCode=rsa.encryptBase64(checkSuccessCode, KeyType.PublicKey);

		redisUtils.set("CheckSuccessCode::"+forgetPasswordVo.getMobile(),checkSuccessCode,2*60);
		return encryptedSuccessCode;
	}

	@Override
	public Object forgetPasswordSetNewPassword(ForgetPasswordVo forgetPasswordVo) {
		//校验手机号
		SysUser sysUser = this.getUserByMobile(forgetPasswordVo.getMobile());
		// 私密解密
		RSA rsa = new RSA(privateKey, null);
		String checkSuccessCode = new String(rsa.decrypt(forgetPasswordVo.getCheckSuccessCode(), KeyType.PrivateKey));
		Object o = redisUtils.get("CheckSuccessCode::" + forgetPasswordVo.getMobile());
		if(o==null){
			throw new BusinessException("验证码校验凭证已经时效，请重新校验");
		}
		if(!checkSuccessCode.equals(o.toString())){
			throw new BusinessException("验证码检验凭证不正确");
		}
		//修改密码
		String newPassword = decryptAES(forgetPasswordVo.getNewPassWord(), sosSecurityProperties.getEncodeKey());
		//修改密码
		sysUser.setPassword(ENCODER.encode(newPassword.trim()));
		this.updateById(sysUser);
		//清理缓存
		this.clearUserDetailCache(sysUser);
		redisUtils.del("CheckSuccessCode::" + forgetPasswordVo.getMobile());
		return true;
	}

	/**
	 * 获取到用户通过手机号
	 * @param mobile
	 * @return
	 */
	private SysUser getUserByMobile(String mobile){
		//校验手机号
		QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
		queryWrapper.lambda().eq(SysUser::getMobile,mobile)
				.last(" limit 1");
		SysUser sysUser = this.getOne(queryWrapper);
		if(sysUser==null){
			throw new BusinessException("当前系统无此手机号用户");
		}
		return sysUser;
	}
	/**
	 * 生成短信验证码并存储.
	 * @return kaptcha
	 */
	private String getKaptcha() {
		StringBuilder str = new StringBuilder();
		Random random = new Random();

		for (int i = 0; i < 4; i++) {
			// 生成一个[0,10)
			int randomInt = random.nextInt(10);
			str.append(randomInt);
		}
		return str.toString();
	}

	@Override
	public Boolean bindMobile(ForgetPasswordVo forgetPasswordVo) {
		//获取到用户信息
		SosUser user = SecurityUtils.getUser();
		if(user==null){
			throw new BusinessException("传入的token信息有误");
		}
		if(StringUtils.isEmpty(forgetPasswordVo.getMobile())){
			throw new BusinessException("请传入手机号");
		}
		//取出验证码
		Object o = redisUtils.get("BindMobileValidCode::" + forgetPasswordVo.getMobile());
		if(o==null){
			throw new BusinessException("请输入正确的验证信息");
		}
		if(!forgetPasswordVo.getValidCode().equals(o.toString())){
			throw new BusinessException("验证码不正确");
		}
		//通过手机号去获取对应的数据
		QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
		queryWrapper.lambda().eq(SysUser::getMobile,forgetPasswordVo.getMobile());
		List<SysUser> list = this.list(queryWrapper);
		if(list!=null&&list.size()>0){
			throw new BusinessException("该手机号："+forgetPasswordVo.getMobile()+" 已经有人使用了");
		}
		//执行手机号绑定
		SysUser sysUser = new SysUser();
		sysUser.setId(user.getUserInfo().getSysUser().getId());
		sysUser.setMobile(forgetPasswordVo.getMobile());
		this.updateById(sysUser);
		//清理缓存
		this.clearUserDetailCache(sysUser.getId());
		//清除手机号验证码缓存
		redisUtils.del("BindMobileValidCode::" + forgetPasswordVo.getMobile());
		return true;
	}

	@Override
	public String getMobile() {
		//获取到用户信息
		SosUser user = SecurityUtils.getUser();
		try{
			SysUser byId = this.getById(user.getId());
			return byId.getMobile();
		}catch (Exception e){
			e.printStackTrace();
		}
		return "";
	}

	@Override
	public Boolean updateUser(UserDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		sysUser.setUpdateTime(LocalDateTime.now());
		//校验手机号是否被其他用户使用
		QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
		queryWrapper.lambda()
				.eq(SysUser::getMobile,userDto.getMobile())
				.ne(SysUser::getId,userDto.getId())
				.last(" limit 1");
		SysUser one = this.getOne(queryWrapper);
		if(one!=null){
			throw new BusinessException("该手机号："+userDto.getMobile()+" 已经有人使用了");
		}
		//获取到最新的拼音信息
		sysUser.setFirstSpell(PinyinUtil.getFirstLetter(sysUser.getName(),""));
		sysUser.setSpell(PinyinUtil.getPinyin(sysUser.getName(),""));
		this.updateById(sysUser);

		sysUserRoleService
				.remove(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, userDto.getId()));
		if(userDto.getRole()!=null){
			userDto.getRole().forEach(roleId -> {
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(sysUser.getId());
				userRole.setRoleId(roleId);
				userRole.insert();
			});
		}
		//删除掉原来的配置
		sysUserDeptService
				.remove(Wrappers.<SysUserDept>update().lambda().eq(SysUserDept::getUserId, userDto.getId()));
		if(userDto.getDept()!=null){
			userDto.getDept().forEach(deptId -> {
				SysUserDept userDept = new SysUserDept();
				userDept.setUserId(sysUser.getId());
				userDept.setDeptId(deptId);
				userDept.insert();
			});
		}
		//清除缓存
		this.clearUserDetailCache(sysUser.getId());
		return Boolean.TRUE;
	}

	@Override
	public Object updateUserStatus(UpdateUserVo updateUserVo) {
		SysUser sysUser = this.getById(updateUserVo.getUserId());
		if(sysUser==null){
			throw new BusinessException("用户信息获取到为空请传入正常的用户id");
		}
		sysUser.setStatus(updateUserVo.getStatus());
		return this.updateById(sysUser);
	}

	@Override
	public Object getDeptUsers(DeptUsersVo deptUsersVo) {
		QueryWrapper queryWrapper=new QueryWrapper();
		queryWrapper.eq("u.STATUS","0");
		queryWrapper.eq(StringUtils.isNotEmpty(deptUsersVo.getContact()),"dept.contact",deptUsersVo.getContact())
				.eq(StringUtils.isNotEmpty(deptUsersVo.getContact()),"u.contact",deptUsersVo.getContact())
				.like(StringUtils.isNotEmpty(deptUsersVo.getDeptPath()),"dept.path",deptUsersVo.getDeptPath());
		List<DeptUsersDto> deptUserList = this.baseMapper.getDeptUsers(queryWrapper);
		//将数据部门分组分组
		Map<String, List<DeptUsersDto>> treeNodeData =
				deptUserList.stream().collect(Collectors.groupingBy(DeptUsersDto::getDeptId));
		//获取到部门数据
		QueryWrapper<SysDept> deptQueryWrapper=new QueryWrapper<>();
		deptQueryWrapper.lambda().select(SysDept::getId,SysDept::getName,SysDept::getSpell,SysDept::getFirstSpell,SysDept::getPath,SysDept::getParentId,SysDept::getSort)
				.eq(StringUtils.isNotEmpty(deptUsersVo.getContact()),SysDept::getContact,deptUsersVo.getContact());
		List<SysDept> deptList = sysDeptMapper.selectList(deptQueryWrapper);
		//构建树结构的数据
		List<TreeNode<Long>> collect = deptList.stream()
				.filter(dept -> dept.getId().intValue() != dept.getParentId())
				.sorted(Comparator.comparingInt(SysDept::getSort)).map(dept -> {
					Map<String,Object> extra=new HashMap<>();
					extra.put("path",dept.getPath());
					extra.put("type","dept");
					extra.put("disabled",true);
					extra.put("children",treeNodeData.get(dept.getId().toString()));
					TreeNode<Long> treeNode = new TreeNode();
					treeNode.setId(dept.getId());
					treeNode.setParentId(dept.getParentId());
					treeNode.setName(dept.getName());
					treeNode.setExtra(extra);
					return treeNode;
				}).collect(Collectors.toList());
		return TreeUtil.build(collect, 0L);
	}


	@Override
	public Object getSelectData(SelectDataVo selectDataVo) {
		// 返回结果集
		Map<String, Object> resultMap = new HashMap<>();
		String[] typesArr = selectDataVo.getTypes().split(",");
		//循环类型获取对应类型的数据
		for (String type : typesArr) {
			//从缓存中获取到数据
			Object data=redisUtils.hget(CacheConstants.SELECT_DATA,type);
			// 本单位
			if (SelectTypeConstants.USER.equals(type)) {
				if(data!=null){
					resultMap.put(type,redisUtils.hget(CacheConstants.SELECT_DATA,SelectTypeConstants.USER));
					continue;
				}
				//从数据库中获取到数据
				DeptUsersVo deptUsersVo=new DeptUsersVo();
				Object deptUsers = this.getDeptUsers(deptUsersVo);
				resultMap.put(type,deptUsers);
				//保存到缓存中
				redisUtils.hset(CacheConstants.SELECT_DATA,type,deptUsers);
			}else if(SelectTypeConstants.DEPT.equals(type)){
				List<Tree<Long>> treeList = sysDeptService.listDeptTrees();
				resultMap.put(type,treeList);
				//保存到缓存中
				redisUtils.hset(CacheConstants.SELECT_DATA,type,treeList);
			}else if(SelectTypeConstants.CUSTOM.equals(type)){
				SosUser user = SecurityUtils.getUser();
				if(user!=null){
					List<CustomGroupDto> customGroupDtoList = sysCustomGroupService.getGroupDataByUserId(user.getId());
					resultMap.put(type,customGroupDtoList);
					//保存到缓存中
					redisUtils.hset(CacheConstants.SELECT_DATA,type,customGroupDtoList);
				}
			}
		}
		return resultMap;
	}

	@Override
	public Object filterTreeData(Map<String, Object> params) {
		String type = (String) params.get("type");
		String name = (String) params.get("name");
		if (StringUtils.isEmpty(type) || StringUtils.isEmpty(name)) {
			throw new BusinessException("必填参数缺失");
		}
		//从缓存中获取到数据
		Object data=redisUtils.hget(CacheConstants.SELECT_DATA,type);
		if(SelectTypeConstants.USER.equals(type)){
			List<Tree<Long>> treeList=(List<Tree<Long>>)data;
			return deepUserDeptFilter(treeList,name);
		}else if(SelectTypeConstants.DEPT.equals(type)){
			List<Tree<Long>> treeList=(List<Tree<Long>>)data;
			return deepFilter(treeList,name);
		} else if(SelectTypeConstants.CUSTOM.equals(type)){
			//todo 自定义组的开发
		}
		return null;
	}

	@Override
	public List<UserVO> getUserListDeptId(Long deptId) {
		UserDTO userDTO=new UserDTO();
		userDTO.setDeptId(deptId);
		List<UserVO> userVosList = this.baseMapper.getUserVosList(userDTO);
		return userVosList;
	}

	@Override
	public List<SysUser> getUserListDeptId(String deptId,String position) {
		QueryWrapper<SysUserDept> queryWrapper=new QueryWrapper<>();
		queryWrapper.lambda().eq(SysUserDept::getDeptId,deptId);
		List<SysUserDept> list = sysUserDeptService.list(queryWrapper);
		Set<Long> idSets = list.stream().map(SysUserDept::getUserId).collect(Collectors.toSet());
		if(idSets!=null&&idSets.size()>0){
			QueryWrapper<SysUser> userQueryWrapper=new QueryWrapper<>();
			userQueryWrapper.lambda().in(SysUser::getId,idSets).eq(StringUtils.isNotEmpty(position),SysUser::getPosition,position);
			return this.list(userQueryWrapper);
		}
		return new ArrayList<>();
	}

	private List<Tree<Long>> deepUserDeptFilter(List<Tree<Long>> treeList, String name) {
		if (treeList == null) {
			return new ArrayList<>();
		}
		List resultData =new ArrayList();
		for (Object data :treeList) {
			if(data instanceof DeptUsersDto){
				DeptUsersDto deptUsersDto =(DeptUsersDto)data;
				// 符合其中一条规则，则不抛弃该节点
				if ((deptUsersDto.getName() != null && deptUsersDto.getName().contains(name)) || (deptUsersDto.getSpell() != null && deptUsersDto.getSpell().contains(name))
						|| (deptUsersDto.getFirstSpell() != null && deptUsersDto.getFirstSpell().contains(name))) {
					resultData.add(deptUsersDto);
				}
			}else if(data instanceof Tree){
				Tree tree =(Tree)data;
				List<Tree<Long>> children = tree.getChildren();
				// 存在子节点，继续遍历；
				if (children != null && children.size() > 0) {
					tree.setChildren(deepUserDeptFilter(children, name));
				}
				// 执行递归遍历之后，仍然存在子节点，说明符合条件，整条完整树需保留
				List<Tree<Long>> children_changed = tree.getChildren();
				if (children_changed != null && children_changed.size() > 0) {
					resultData.add(tree);
					continue;
				}
			}
		}
		return resultData;
	}

	/**
	 * 递归过滤树结构的
	 * @param treeList
	 * @param name
	 * @return
	 */
	private List<Tree<Long>> deepFilter(List<Tree<Long>> treeList, String name){
		if (treeList == null) {
			return new ArrayList<>();
		}
		for (Tree tree :treeList) {
			List<Tree<Long>> children = tree.getChildren();
			// 存在子节点，继续遍历；
			if (children != null && children.size() > 0) {
				tree.setChildren(deepFilter(children, name));
			}
			// 执行递归遍历之后，仍然存在子节点，说明符合条件，整条完整树需保留
			List<Tree<Long>> children_changed = tree.getChildren();
			if (children_changed != null && children_changed.size() > 0) {
				tree.putExtra("abandon",false);
				continue;
			}
			// 中文名
			String orginName = (String) tree.getName();
			// 中文名全拼
			String spell = (String) tree.get("spell");
			// 中文名首字母
			String firstSpell = (String) tree.get("firstSpell");
			// 符合其中一条规则，则不抛弃该节点
			if ((orginName != null && orginName.contains(name)) || (spell != null && spell.contains(name))
					|| (firstSpell != null && firstSpell.contains(name))) {
				tree.putExtra("abandon", false);
			} else {
				tree.putExtra("abandon", true);
			}
		}
		List<Tree<Long>> result = treeList.stream().filter(item -> !Boolean.valueOf(String.valueOf(item.get("abandon")))).collect(Collectors.toList());
		return result;
	}

	@Override
	public void clearUserDetailCache(SysUser sysUser) {
		try{
			Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
			if(cache!=null){
				if(StringUtils.isNotEmpty(sysUser.getUsername())){
					cache.evictIfPresent(sysUser.getUsername());
				}
				if(StringUtils.isNotEmpty(sysUser.getMobile())){
					cache.evictIfPresent(sysUser.getMobile());
				}
				if(StringUtils.isNotEmpty(sysUser.getZDingAccountId())){
					cache.evictIfPresent(sysUser.getZDingAccountId());
				}
				//获取到全部客户端的信息
				QueryWrapper<SysOauthClientDetails> queryWrapper=new QueryWrapper<>();
				queryWrapper.lambda().select(SysOauthClientDetails::getClientId);
				List<SysOauthClientDetails> sysOauthClientDetailsList = sysOauthClientDetailsMapper.selectList(queryWrapper);
				if(sysOauthClientDetailsList!=null&&sysOauthClientDetailsList.size()>0){
					Set<String> clientIds = sysOauthClientDetailsList.stream().map(item -> item.getClientId()).collect(Collectors.toSet());
					//修改token中的信息
					sosAuthProvider.setNewUserInfoByUserName(sysUser.getUsername(),clientIds);
				}
			}
			this.clearSelectUserData();
		}catch (Exception e){
		}
	}

	@Override
	public void clearUserToken(SysUser sysUser) {
		try{
			Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
			if(cache!=null){
				if(StringUtils.isNotEmpty(sysUser.getUsername())){
					cache.evictIfPresent(sysUser.getUsername());
				}
				if(StringUtils.isNotEmpty(sysUser.getMobile())){
					cache.evictIfPresent(sysUser.getMobile());
				}
				if(StringUtils.isNotEmpty(sysUser.getZDingAccountId())){
					cache.evictIfPresent(sysUser.getZDingAccountId());
				}
			}
			//获取到全部客户端的信息
			QueryWrapper<SysOauthClientDetails> queryWrapper=new QueryWrapper<>();
			queryWrapper.lambda().select(SysOauthClientDetails::getClientId);
			List<SysOauthClientDetails> sysOauthClientDetailsList = sysOauthClientDetailsMapper.selectList(queryWrapper);
			if(sysOauthClientDetailsList!=null&&sysOauthClientDetailsList.size()>0){
				Set<String> clientIds = sysOauthClientDetailsList.stream().map(item -> item.getClientId()).collect(Collectors.toSet());
				//修改token中的信息
				sosAuthProvider.removeTokenByUserName(sysUser.getUsername(),clientIds);
			}
			this.clearSelectUserData();
		}catch (Exception e){
		}
	}

	private void clearSelectUserData(){
		//删除掉选人组件的缓存
		redisUtils.hdel(CacheConstants.SELECT_DATA,SelectTypeConstants.USER);
	}
	@Override
	public boolean updateOpenCodeByUserId(Long userId, String openCode) {
		SysUser sysUser = new SysUser();
		sysUser.setId(userId);
		sysUser.setOpenCode(openCode);

		int i = baseMapper.updateById(sysUser);
		clearUserDetailCache(userId);
		return i == 1;
	}

	@Override
	public Object getValidCode(ForgetPasswordVo forgetPasswordVo) {
			//校验手机号
			QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
			queryWrapper.lambda().eq(SysUser::getMobile,forgetPasswordVo.getMobile())
				.last(" limit 1");
			SysUser sysUser = this.getOne(queryWrapper);
			if(sysUser!=null){
				throw new BusinessException("当前系统手机号已被使用");
			}
			//查看缓存中验证码是否还有效
			Object o = redisUtils.get("BindMobileValidCode::" + forgetPasswordVo.getMobile());
			if(o!=null){
				// todo 目前没有短信机直接返回验证码，后续有短信机把返回值去掉
				return String.valueOf(o);
			}
			//获取到验证码
			String kaptcha = this.getKaptcha();
			//发送短信验证码 todo 根据你的短信机
			//保存到redis,时效1分钟
			redisUtils.set("BindMobileValidCode::"+forgetPasswordVo.getMobile(),kaptcha,1*60);
			// todo 发送短信
			// todo 目前没有短信机直接返回验证码，后续有短信机把返回值去掉
			return kaptcha;
	}

	@Override
	public List<UserVO> getRoleUsers(Long roleId) {
		List<UserVO> userVosList = this.baseMapper.getUserVoByRoleId(roleId);
		return userVosList;
	}

	/**
	 * 清理缓存 (根据是否是完整的用户参数来选择哪个接口)
	 * @param id
	 */
	private void clearUserDetailCache(Long id) {
		SysUser sysUser = this.getById(id);
		this.clearUserDetailCache(sysUser);
	}

	private static String decryptAES(String data, String pass) {
		AES aes = new AES(Mode.CBC, Padding.NoPadding, new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM),
				new IvParameterSpec(pass.getBytes()));
		byte[] result = aes.decrypt(Base64.decode(data.getBytes(StandardCharsets.UTF_8)));
		return new String(result, StandardCharsets.UTF_8);
	}
}
